package com.chat.common.chat.service.impl;

import com.chat.common.chat.dao.*;
import com.chat.common.chat.domain.entity.Room;
import com.chat.common.chat.domain.entity.RoomGroup;
import com.chat.common.chat.domain.vo.request.admin.AdminAddReq;
import com.chat.common.chat.domain.vo.request.admin.AdminRevokeReq;
import com.chat.common.chat.domain.vo.request.member.MemberExitReq;
import com.chat.common.chat.service.IGroupMemberService;
import com.chat.common.chat.service.adapter.MemberAdapter;
import com.chat.common.chat.service.cache.GroupMemberCache;
import com.chat.common.chat.service.cache.RoomCaChe;
import com.chat.common.chat.service.cache.RoomGroupCache;
import com.chat.common.chat.service.exception.GroupErrorEnum;
import com.chat.common.common.domain.enums.CommonErrorEnum;
import com.chat.common.common.utils.AssertUtil;
import com.chat.common.user.service.cache.UserInfoCache;
import com.chat.common.user.service.impl.PushService;
import com.chat.common.websocket.domain.enums.WSBaseResp;
import com.chat.common.websocket.domain.vo.resp.ws.WSMemberChange;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

@Service
public class GroupMemberServiceImpl implements IGroupMemberService {
    @Resource
    private RoomGroupDao roomGroupDao;
    @Resource
    private RoomDao roomDao;
    @Resource
    private GroupMemberDao groupMemberDao;
    @Resource
    private ContactDao contactDao;
    @Resource
    private MessageDao messageDao;
    @Resource
    private GroupMemberCache groupMemberCache;
    @Resource
    private PushService pushService;
    @Resource
    private RoomCaChe roomCaChe;
    @Autowired
    private UserInfoCache userInfoCache;
    @Autowired
    private RoomGroupCache roomGroupCache;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void exitGroup(Long uid, MemberExitReq request) {
        Long roomId = request.getRoomId();
        // 1. 判断群聊是否存在
        RoomGroup roomGroup = roomGroupDao.getByRoomId(roomId);
        AssertUtil.isNotEmpty(roomGroup, GroupErrorEnum.GROUP_NOT_EXIST);
        // 2. 判断房间是否是大群聊 （大群聊禁止退出）
        Room room = roomDao.getById(roomId);
        AssertUtil.isFalse(room.isHotRoom(),GroupErrorEnum.NOT_ALLOWED_FOR_EXIT_GROUP);
        // 3. 判断群成员是否在群中
        boolean groupShip = groupMemberDao.isGroupShip(roomGroup.getRoomId(), Collections.singletonList(uid));
        AssertUtil.isTrue(groupShip,GroupErrorEnum.USER_NOT_IN_GROUP);
        // 4. 判断该用户是否是群主
        boolean lord = groupMemberDao.isLord(uid, roomGroup.getId());
        //是群主 则 删除房间 会话 成员 删除消息记录
        if (lord){
            //删除房间
            boolean b = roomDao.removeById(roomId);
            AssertUtil.isTrue(b, CommonErrorEnum.SYSTEM_ERROR);
            //删除会话
            boolean isDelContact= contactDao.removeByRoomId(roomId,Collections.EMPTY_LIST);
            AssertUtil.isTrue(isDelContact, CommonErrorEnum.SYSTEM_ERROR);
            // 4.3 删除群成员
            Boolean isDelGroupMember = groupMemberDao.removeByGroupId(roomGroup.getId(), Collections.EMPTY_LIST);
            AssertUtil.isTrue(isDelGroupMember, CommonErrorEnum.SYSTEM_ERROR);
            // 4.4 删除消息记录 (逻辑删除)
            Boolean isDelMessage = messageDao.removeByRoomId(roomId, Collections.EMPTY_LIST);
            AssertUtil.isTrue(isDelMessage, CommonErrorEnum.SYSTEM_ERROR);
        }else {
            // 4.5 删除会话
            Boolean isDelContact = contactDao.removeByRoomId(roomId, Collections.singletonList(uid));
            AssertUtil.isTrue(isDelContact, CommonErrorEnum.SYSTEM_ERROR);
            // 4.6 删除群成员
            Boolean isDelGroupMember = groupMemberDao.removeByGroupId(roomGroup.getId(), Collections.singletonList(uid));
            AssertUtil.isTrue(isDelGroupMember, CommonErrorEnum.SYSTEM_ERROR);
            // 4.7 发送移除事件告知群成员
            List<Long> memberUidList = groupMemberCache.getMemberUidList(roomGroup.getRoomId());
            WSBaseResp<WSMemberChange> ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), uid);
            pushService.sendPushMsg(ws, memberUidList);
            groupMemberCache.evictMemberUidList(room.getId());

        }
    }

    @Override
    public void addAdmin(Long uid, AdminAddReq request) {
        RoomGroup roomGroup = isExist(request.getRoomId(), uid, request.getUidList());

        // 4. 判断管理员数量是否达到上限
        // 4.1 查询现有管理员数量
        List<Long> manageUidList = groupMemberDao.getManageUidList(roomGroup.getId());
        // 4.2 去重
        HashSet<Long> manageUidSet = new HashSet<>(manageUidList);
        manageUidSet.addAll(request.getUidList());
        AssertUtil.isFalse(manageUidSet.size() > 3, GroupErrorEnum.MANAGE_COUNT_EXCEED);

        // 5. 增加管理员
        groupMemberDao.addAdmin(roomGroup.getId(), request.getUidList());

    }

    @Override
    public void revokeAdmin(Long uid, AdminRevokeReq request) {
        RoomGroup roomGroup = isExist(request.getRoomId(), uid, request.getUidList());
        // 4. 撤销管理员
        groupMemberDao.revokeAdmin(roomGroup.getId(), request.getUidList());
    }

    /**
     * 判断群聊是否存在 申请操作的用户是否是群主 被操作的用户是否是群成员
     * @param roomId
     * @param uid
     * @param uidList
     * @return
     */
    public RoomGroup isExist(Long roomId, Long uid, List<Long> uidList) {
        // 1. 判断群聊是否存在
        RoomGroup roomGroup = roomGroupDao.getByRoomId(roomId);
        AssertUtil.isNotEmpty(roomGroup, GroupErrorEnum.GROUP_NOT_EXIST);
        // 2. 判断该用户是否是群主
        boolean isLord = groupMemberDao.isLord(uid, roomGroup.getId());
        AssertUtil.isTrue(isLord, GroupErrorEnum.NOT_ALLOWED_OPERATION);
        // 3. 判断群成员是否在群中
        boolean isGroupShip = groupMemberDao.isGroupShip(roomGroup.getRoomId(), uidList);
        AssertUtil.isTrue(isGroupShip, GroupErrorEnum.USER_NOT_IN_GROUP);
        return roomGroup;
    }
}
